﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Solidi
{
    public class GenericDependencyResolver : IDependencyResolver 
    {
        private IDependencyResolver _resolver;
        private Type _genericType;
        private Type _builderType;

        public GenericDependencyResolver(IDependencyResolver resolver, Type genericType, Type builderType)
		{
			if (resolver == null)
			{
				throw new ArgumentNullException("resolver");
			}

            if (genericType == null)
			{
                throw new ArgumentNullException("genericType");
			}

            if (builderType == null)
            {
                throw new ArgumentNullException("builderType");
            }

            _resolver = resolver;
            _genericType = genericType;
            _builderType = builderType;
		}

        public bool TryResolve(object graphId, IDependencyContainer container, IDependencyKey key, out object instance)
		{
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

			if (!_resolver.TryResolve(graphId, container, key, out instance))
			{
                Type type = key.Type;

                if (type.IsGenericType)
                {
                    if (_genericType == type.GetGenericTypeDefinition())
					{
                        Type[] typeArguments = type.GetGenericArguments();

                        if (typeArguments.Length == 1)
                        {
                            Type returnType = typeArguments[0];

                            GenericDependencyFactory builder = (GenericDependencyFactory)Activator.CreateInstance(_builderType.MakeGenericType(returnType));

                            instance = builder.Build(container, new DependencyKey(returnType, key.Name));

                            return instance != null;
                        }
                    }
                }

                return false;
            }

            return true;
        }

        public bool TryResolve(IDependencyContainer container, IDependencyKey key, out object instance)
		{
			return _resolver.TryResolve(container, key, out instance);
		}

		public bool TryRelease(IDependencyContainer container, object instance)
		{
			return _resolver.TryRelease(container, instance);
		}
    }
}
